/*  see copyright notice in squirrel.h */
#ifndef _SQARRAY_H_
#define _SQARRAY_H_

struct SQArray : public CHAINABLE_OBJ
{
private:
	SQArray(SQSharedState *ss, SQInteger nsize)
	{
		_values.resize(nsize);
		INIT_CHAIN();
		ADD_TO_CHAIN(&_ss(this)->_gc_chain, this);
	}
	~SQArray()
	{
		REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this);
	}

public:
	static SQArray *Create(SQSharedState *ss, SQInteger nInitialSize)
	{
		SQArray *newarray = (SQArray *)SQ_MALLOC(sizeof(SQArray));
		new(newarray) SQArray(ss, nInitialSize);
		return newarray;
	}
#ifndef NO_GARBAGE_COLLECTOR
	void Mark(SQCollectable **chain);
	SQObjectType GetType()
	{
		return OT_ARRAY;
	}
#endif
	void Finalize()
	{
		_values.resize(0);
	}
	bool Get(const SQInteger nidx, SQObjectPtr &val)
	{
		if(nidx >= 0 && nidx < (SQInteger)_values.size()) {
			SQObjectPtr &o = _values[nidx];
			val = _realval(o);
			return true;
		} else
			return false;
	}
	bool Set(const SQInteger nidx, const SQObjectPtr &val)
	{
		if(nidx >= 0 && nidx < (SQInteger)_values.size()) {
			_values[nidx] = val;
			return true;
		} else
			return false;
	}
	SQInteger Next(
			const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
	{
		SQUnsignedInteger idx = TranslateIndex(refpos);
		while(idx < _values.size()) {
			//first found
			outkey = (SQInteger)idx;
			SQObjectPtr &o = _values[idx];
			outval = _realval(o);
			//return idx for the next iteration
			return ++idx;
		}
		//nothing to iterate anymore
		return -1;
	}
	SQArray *Clone()
	{
		SQArray *anew = Create(_opt_ss(this), 0);
		anew->_values.copy(_values);
		return anew;
	}
	SQInteger Size() const
	{
		return _values.size();
	}
	void Resize(SQInteger size)
	{
		SQObjectPtr _null;
		Resize(size, _null);
	}
	void Resize(SQInteger size, SQObjectPtr &fill)
	{
		_values.resize(size, fill);
		ShrinkIfNeeded();
	}
	void Reserve(SQInteger size)
	{
		_values.reserve(size);
	}
	void Append(const SQObject &o)
	{
		_values.push_back(o);
	}
	void Extend(const SQArray *a);
	SQObjectPtr &Top()
	{
		return _values.top();
	}
	void Pop()
	{
		_values.pop_back();
		ShrinkIfNeeded();
	}
	bool Insert(SQInteger idx, const SQObject &val)
	{
		if(idx < 0 || idx > (SQInteger)_values.size())
			return false;
		_values.insert(idx, val);
		return true;
	}
	void ShrinkIfNeeded()
	{
		if(_values.size() <= _values.capacity() >> 2) //shrink the array
			_values.shrinktofit();
	}
	bool Remove(SQInteger idx)
	{
		if(idx < 0 || idx >= (SQInteger)_values.size())
			return false;
		_values.remove(idx);
		ShrinkIfNeeded();
		return true;
	}
	void Release()
	{
		sq_delete(this, SQArray);
	}

	SQObjectPtrVec _values;
};
#endif //_SQARRAY_H_
